package com.wingsfrog.puzzle.controller;

import com.wingsfrog.puzzle.base.BaseController;
import com.wingsfrog.puzzle.controller.dto.response.*;
import com.wingsfrog.puzzle.modules.dao.PuzzlesDao;
import com.wingsfrog.puzzle.modules.entity.Picture;
import com.wingsfrog.puzzle.modules.entity.Puzzles;
import com.wingsfrog.puzzle.modules.entity.User;
import com.wingsfrog.puzzle.service.PictureService;
import com.wingsfrog.puzzle.service.PuzzleRecordService;
import com.wingsfrog.puzzle.service.PuzzlesService;
import com.wingsfrog.puzzle.service.UserService;
import com.wingsfrog.puzzle.util.ImageUtil;
import com.wingsfrog.puzzle.util.PuzzleUtil;
import com.wingsfrog.puzzle.util.QiniuUtil;
import com.wingsfrog.puzzle.util.wechat.WeiXinUtil;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.sql.Timestamp;
import java.util.*;

@RestController
@RequestMapping(value = "image")
public class ImageController extends BaseController {
    @Autowired
    PictureService pictureService;
    @Autowired
    PuzzleRecordService recordService;
    @Autowired
    UserService userService;
    @Autowired
    PuzzlesService puzzlesService;
    @Autowired
    PuzzlesDao puzzlesDao;

    private Logger logger = Logger.getLogger(ImageController.class);

    private void fullfillDto(SmallPictureDto dto, Integer userId, Integer picId) {
        if (userId != null) {
            User user = userService.get(userId);
            if (user != null) {
                dto.setAvatar(user.getAvatar());
                dto.setNickname(user.getNickname());
                dto.setCoins(user.getCoins());
            }
        }
        if (picId != null) {
            dto.setPicId(picId);
            List<RecordDto> scoreBoard = recordService.getScoreBoard(picId);
            dto.setScoreboard(scoreBoard);
        }
    }

    @RequestMapping(value = "upload", method = {RequestMethod.GET})
    @Transactional
    public SmallPictureDto uploadImage(@RequestParam("mediaId") String mediaId,
                                       HttpServletRequest request) throws Exception {
        String weiXinToken = WeiXinUtil.getWeixinToken();
        Integer userId = (Integer) request.getSession().getAttribute("userId");
        String _url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token="
                + weiXinToken + "&media_id=" + mediaId;
        URL url = new URL(_url);
        String fileName = UUID.randomUUID().toString();
        File f = new File("/tmp/puzzle/" + fileName);
        boolean newFile = f.createNewFile();
        FileUtils.copyURLToFile(url, f);

        QiniuUtil.upload(f, fileName); // 上传到 CDN
        ImageUtil.cutImage(f, 3, fileName);
        f.delete();

        SmallPictureDto dto = new SmallPictureDto();
        dto.setOriImg("http://c.wingsfrog.com/" + fileName);
        List<Map<String, String>> list = new ArrayList<>();
        for (Integer i = 0; i < 9; i++) {
            Map<String, String> map = new HashMap<>();
            map.put("id", "1" + i.toString());
            map.put("url", "http://c.wingsfrog.com/" + fileName + "_" + i.toString());
            list.add(map);
        }
        dto.setList(list);

        Puzzles puzzles = puzzlesService.getByHardness(5);
        PuzzleUtil.disarrange(puzzles.getHash(), list);
        dto.setBlackId(puzzles.getBlank());

        Picture picture = new Picture();
        picture.setCreatedAt(new Timestamp(System.currentTimeMillis()));
        picture.setPath(dto.getOriImg());
        picture.setUserId(userId); //微信用户的openId
        pictureService.save(picture);

        fullfillDto(dto, userId, picture.getId());
        return dto;
    }

    @RequestMapping(value="get_pic", method = {RequestMethod.GET})
    @Transactional
    public SmallPictureDto getImage(@RequestParam("picId") Integer picId,
                                    @RequestParam(name = "hardness") Integer hardness,
                                    HttpServletRequest request) {
        logger.info("getImage(picId=" + picId + ", hardness=" + hardness + ")");
        if (picId == null) picId = 0;
        Picture picture = pictureService.get(picId);
        if (picture == null) {
            logger.warn(String.format("图片%d不存在", picId));
            picId = 0;
            picture = pictureService.get(0);
        }
        SmallPictureDto dto = new SmallPictureDto();
        if (picture != null) {
            dto.setOriImg(picture.getPath());
            List<Map<String, String>> list = new ArrayList<>();
            for (Integer i = 0; i < 9; i++) {
                Map<String, String> map = new HashMap<>();
                map.put("id", "1" + i.toString());
                map.put("url", picture.getPath() + "_" + i.toString());
                list.add(map);
            }
            dto.setList(list);
            if (hardness == null) hardness = 10;
            Puzzles puzzles = puzzlesService.getByHardness(hardness);
            PuzzleUtil.disarrange(puzzles.getHash(), list);
            logger.info("puzzleId=" + puzzles.getId());
            dto.setBlackId(puzzles.getBlank());
        }

        Integer userId = (Integer) request.getSession().getAttribute("userId");
        logger.info("userId=" + userId);
        fullfillDto(dto, userId, picId);
        return dto;
    }

    @RequestMapping(value="upload_score", method = {RequestMethod.GET})
    @Transactional
    public Object uploadScore(@RequestParam("picId") Integer picId,
                              @RequestParam("step") Integer step,
                              @RequestParam("time") Integer time,
                              HttpServletRequest request) {
        logger.info("uploadScore(picId=" + picId.toString() +
                ", step=" + step.toString() + ", time=" + time + ")");
        if (time != null && step < 10000 && time < 10000) {
            Integer userId = (Integer) request.getSession().getAttribute("userId");
            User user = userService.get(userId);
            recordService.update(user.getId(), picId, step, time);
        }

        List<RecordDto> scoreBoard = recordService.getScoreBoard(picId);
        return scoreBoard;
    }

    @RequestMapping(value="get_ans", method={RequestMethod.GET})
    public Object getAnswer(@RequestParam("picHash") Long picHash,
                            @RequestParam("o") Long o,
                            @RequestParam("blank") int start,
                            HttpServletRequest request ) {
        picHash |= o << 32;
        Puzzles puzzles = puzzlesService.getByHash(picHash, start);

        Map<String, String> res = new HashMap<>();
        Integer userId = (Integer) request.getSession().getAttribute("userId");
        User user = userService.get(userId);
        if (puzzles != null) {
            res.put("step", puzzles.getSolves());
            user.setCoins(user.getCoins() - 5);
            userService.saveUser(user);
        }
        res.put("coins", String.valueOf(user.getCoins()));
        return res;
    }

    @RequestMapping(value = "user_info", method = {RequestMethod.GET})
    public UserInfoDto getUserInfo(@RequestParam(name = "userId", required = false)
                                       Integer userId,
                                   HttpServletRequest request) {
        if (userId == null)
            userId = (Integer) request.getSession().getAttribute("userId");
        UserInfoDto userInfoDto = new UserInfoDto();
        User user = userService.get(userId);
        userInfoDto.setAvatar(user.getAvatar());
        userInfoDto.setNickname(user.getNickname());
        userInfoDto.setPlayList(recordService.getPlayList(userId));
        userInfoDto.setOccupyList(recordService.getOccupyList(userId));
        return userInfoDto;
    }

    // 返回玩过某图的所有玩家
    @RequestMapping(value="get_pic_play_list", method = {RequestMethod.GET})
    public List<UserResDto> getPicPlayList(@RequestParam("picId") Integer picId) {
        List<UserResDto> userList = recordService.getUserList(picId);
        return userList;
    }

    /*
    @RequestMapping(value="generate", method = {RequestMethod.GET})
    public void generate() throws IOException {
        List<Long> hashList = new ArrayList<>();
        int[] defaultGrids = {0,1,2,3,4,5,6,7,8};
        hashList.add(hashGrid(defaultGrids));

        List<PuzzleUtil.State> states = new ArrayList<>();
        for(int i = 0; i < 9; i++) { // 初始化状态
            states.add(new PuzzleUtil.State(defaultGrids, i, new ArrayList<PuzzleUtil.DIRECTION>(), -1));
        }
        File f = new File("/Users/ztyu/test.txt");
        f.createNewFile();
        OutputStream tmpStream = new FileOutputStream(f);
        ObjectOutputStream stream = new ObjectOutputStream(tmpStream);

        for (int i = 0; i < states.size(); i++) {
            PuzzleUtil.State state = states.get(i);
            for (PuzzleUtil.DIRECTION direction : PuzzleUtil.DIRECTION.values()) {
                if (canGo(direction, state.xPos)) {

                    int newPos = state.xPos + direction.getDelta();
                    int[] newGrids = state.grids.clone();
                    newGrids[newPos] = state.grids[state.xPos];
                    newGrids[state.xPos] = state.grids[newPos];

                    Long hash = hashGrid(newGrids);
                    if (!hashList.contains(hash)) {
                        hashList.add(hash);
                        PuzzleUtil.State newState = new PuzzleUtil.State(newGrids, newPos, null, -1);
                        Puzzles puzzle = new Puzzles();
                        puzzle.setBlank(newPos);
                        puzzle.setHash(hash);
                        stream.writeObject(puzzle);
//                        System.out.println(hashList.size());
//                        puzzlesDao.save(puzzle);
                        states.add(newState);
                    }
                }
            }
        }
        System.out.println(states.size());
    }

    @RequestMapping(value="import", method={RequestMethod.GET})
    public void importToDb() throws IOException {
        ObjectInputStream stream = null;
        File f = new File("/Users/ztyu/test.txt");
        try {
            stream = new ObjectInputStream(new FileInputStream(f));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Integer i = 0;
        File wFile = new File("/Users/ztyu/sql");
        FileOutputStream wStream = new FileOutputStream((wFile));
        try {
            wStream.write("insert into puzzles (blank, hash) values \n".getBytes());
            while(true) {
                i++;
                Puzzles p = (Puzzles)stream.readObject();
                String s = String.format("(%d, %d)",
                        p.getBlank(),
                        p.getHash());
                wStream.write(s.getBytes());
                if (i % 100 == 0) {
                    wStream.write(";\ninsert into puzzles (blank, hash) values ".getBytes());
                } else {
                    wStream.write(",\n".getBytes());
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            wStream.write(";".getBytes());
            e.printStackTrace();
            return;
        }
    }
    */

}
